#include "LaserReflector.h"

#include "../SGD Wrappers/CSGD_Direct3D.h"
#include "Camera.h"
#include "Physics.h"
#include "Events\Event.h"

#ifndef TWO_PI
#define TWO_PI 6.2831852f
#endif

#ifndef PI
#define PI 3.1415926f
#endif

// Constructor
LaserReflector::LaserReflector(void)
{
	objectID = "Laser Reflector";

	normal.fX = startNormal.fX = -0.5f;
	normal.fY = startNormal.fY = 0.5f;

	surfaceLine = normal;
	surfaceLine.fX *= -1;
	startSurfaceLine = surfaceLine;

	rotation = 0.0f;

	reflectedLaser = false;
	autoRotate = false;
}

// Destructor
LaserReflector::~LaserReflector(void)
{
}

void LaserReflector::Update(float deltaTime)
{
	if(autoRotate == true)
		Rotate(0.2f * deltaTime * (rotateClockwise ? 1 : -1));
}

void LaserReflector::Render(void) const
{
	float centerX = (float)((hitBox.right - hitBox.left) >> 1);
	float centerY = (float)((hitBox.bottom - hitBox.top) >> 1);
	CSGD_TextureManager::GetInstance()->Draw(imageID, 
		(int)(hitBox.left - Camera::GetInstance()->OffsetX()),
		(int)(hitBox.top - Camera::GetInstance()->OffsetY()), 
		1.0f, 1.0f, nullptr, centerX, centerY, rotation);

	if(reflectedLaser == true)
	{
		DrawLaser(
			(int)(renderPoint.fX - Camera::GetInstance()->OffsetX()),
			(int)(renderPoint.fY - Camera::GetInstance()->OffsetY()),
			(int)(renderPoint.fX + (int)(renderDirection.fX * renderDist) - Camera::GetInstance()->OffsetX()),
			(int)(renderPoint.fY + (int)(renderDirection.fY * renderDist) - Camera::GetInstance()->OffsetY()),
			5
			);
		reflectedLaser = false;
	}

#if 0
	CSGD_Direct3D::GetInstance()->DrawLine(
		hitBox.left + (int)centerX - (int)Camera::GetInstance()->OffsetX(), 
		hitBox.top + (int)centerY - (int)Camera::GetInstance()->OffsetY(), 
		hitBox.left + (int)(centerX + normal.fX * 50.0f - Camera::GetInstance()->OffsetX()),
		hitBox.top + (int)(centerY + normal.fY * 50.0f - Camera::GetInstance()->OffsetY()),
		D3DCOLOR_ARGB(255, 0, 0, 255), 1);
#endif
}

void LaserReflector::HandleEvent(Event* e)
{
	vector<string>* tags = getSenderTags(e->GetEventID());

	for(unsigned int i = 0; i < tags->size(); ++i)
	{
		if(((GameObject*)e->GetSender())->GetTag() == (*tags)[i])
		{
			if(e->GetEventID() == "ButtonActivated")
				autoRotate = true;
			else if(e->GetEventID() == "ButtonDeactivated")
				autoRotate = false;
			break;
		}
	}
}

void LaserReflector::ResetToCheckPoint()
{

}

// ReflectLaser
// Parameters:
//		direction	- A normalized vector representing the direction the laser is hitting the reflector from.
//		point		- The point where the laser hit the receiver.
//		range		- The maximum range of the reflected laser beam.
// Return: GameObject*
//		- A pointer to the object that was hit by the laser.
//		  If no object was hit, the return is NULL.
GameObject* LaserReflector::ReflectLaser(tVector2D direction, tVector2D point, float range, LinecastInfo& info)
{
	if(DotProduct(direction, normal) > 0.0f)
		return nullptr;

	renderDirection = (direction * 1) - (normal * (2 * DotProduct(direction, normal)));

	float centerX = (float)hitBox.left + ((hitBox.right - hitBox.left) >> 1);
	float centerY = (float)hitBox.top + ((hitBox.bottom - hitBox.top) >> 1);
	tVector2D c = { centerX, centerY };
	//tVector2D p = c - surfaceLine * 16;
	//tVector2D p2 = c + surfaceLine * 16;
	tVector2D p = { (float)hitBox.right, (float)hitBox.bottom };
	tVector2D p2 = { (float)hitBox.left, (float)hitBox.top };

	surfaceLine = p - p2;

	surfaceLine = Vector2DNormalize(surfaceLine);
	surfaceLine = Vector2DRotate(surfaceLine, rotation);

	p = c - surfaceLine * 32;
	p2 = c + surfaceLine * 32;

	//Physics::RotatePoint(c, p, rotation);
	//Physics::RotatePoint(c, p2, rotation);

	bool didCollide = false;
	tVector2D linePoint = Physics::LineCollision(point, point + direction * 50.0f, p, p2, &didCollide);
	
	LinecastInfo hitInfo;
	if(didCollide && Physics::LineCast(hitInfo, range, linePoint, renderDirection, this))
	{
		renderPoint = linePoint;
		renderDist = Vector2DLength(hitInfo.point - linePoint);

		reflectedLaser = true;
		info = hitInfo;

		if(info.GetObjectHit()->GetObjectID() == objectID)
		{
			LaserReflector* reflector = dynamic_cast<LaserReflector*>(info.GetObjectHit());

			if(reflector != nullptr)
				return reflector->ReflectLaser(renderDirection, hitInfo.point, range - renderDist, info);
		}

		return hitInfo.GetObjectHit();
	}

	return nullptr;
}

void LaserReflector::Rotate(float rotation)
{
	this->rotation += rotation;

	for(; this->rotation > TWO_PI; this->rotation -= TWO_PI);
	for(; this->rotation < 0.0f; this->rotation += TWO_PI);

	//normal = startNormal;
	//surfaceLine = startSurfaceLine;

	normal = Vector2DRotate(startNormal, this->rotation);
	surfaceLine = Vector2DRotate(startSurfaceLine, this->rotation);
}

void LaserReflector::SetNormal(float x, float y)
{
	this->normal.fX = x;
	this->normal.fY = y;

	normal = Vector2DNormalize(normal);
	startNormal = normal;

	surfaceLine = normal;
	surfaceLine.fX *= -1;
	startSurfaceLine = surfaceLine;
}

void LaserReflector::SetNormal(tVector2D normal)
{
	this->normal = normal;

	normal = Vector2DNormalize(normal);
	startNormal = normal;

	surfaceLine = normal;
	surfaceLine.fX *= -1;
	startSurfaceLine = surfaceLine;
}

void LaserReflector::AutoRotate(bool rotate)
{
	this->autoRotate = rotate;
}

void LaserReflector::RotateClockwise(bool clockwise)
{
	this->rotateClockwise = clockwise;
}

// A recursive helper method that renders the laser beam with a jagged effect.
void LaserReflector::DrawLaser(int x1, int y1, int x2, int y2, int iterations) const
{
	if(iterations > 0)
	{
		int newX = ((x1 + x2) >> 1) + (rand() % 8) - 4;
		int newY = ((y1 + y2) >> 1) + (rand() % 8) - 4;

		DrawLaser(x1, y1, newX, newY, iterations - 1);
		DrawLaser(newX, newY, x2, y2, iterations - 1);
	}
	else
	{
		CSGD_Direct3D::GetInstance()->DrawLine(x1, y1, x2, y2, D3DCOLOR_ARGB(255, 215 + (rand() % 80) - 40, 215 + (rand() % 80) - 40, 0), 5);
	}
}